#ifndef STLMODELWIDGET_H
#define STLMODELWIDGET_H

#include <QWidget>
// #include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions_ES2>
#include <QtOpenGLWidgets/QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QFile>
#include <QTextStream>
#include <QPair>
#include <QPainter>

#include <limits.h>
#include <memory>

#include "STLReader.h"
#include "ViewCamera.h"
#include "ModelFormation.h"
#include "STLModelAttributesCalculator.h"
#include "STLModelMeshesConvertor.h"

class STLModelWidget : public QOpenGLWidget, QOpenGLFunctions_ES2//protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT

public:
    STLModelWidget(std::shared_ptr<STLReader> stl_reader, QWidget *parent = nullptr);
    ~STLModelWidget();

public:
    QVector3D getCurrentCameraPos();
    QVector3D transformNormalToModelSpace(const QVector3D& viewNormal);
    bool saveFramebufferToPNG(const QString &filePath);

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

private:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;
    void keyPressEvent(QKeyEvent* event) override;

private:
    bool loadShaderSource(const QString &filePath, QString &source);
    bool compileAndLinkShaders(QOpenGLShaderProgram *p_program, const QString& vs_file_path, const QString& fs_file_path);
    void setModelShaderProgramDataFormation();
    void setCoordSysShaderProgramDataFormation();
    void prepareCoordSysData();
    void setModelVertexData2Shader(const QVector<Vertex>& model_vertices);
    void setCoordSysVertexData2Shader();
    void calAndSetModelInitPhase(bool isFlip);

private:
    // 以下方法归入另一个拟合切片类管理
    // sortPointsByProjectionLengthAlongDirection负责产生有序的粗糙切片（未按照分割平面平整化）
    // reArrangePointsByLayersTier负责按有序切片的大到小或者相反方向重构回顶点数组，用于输入GPU
    QVector<Layer> sortPointsByProjectionLengthAlongDirection(const QVector<Vertex>& model_points, QVector3D norm_direction, float sliceThickness);
    QVector<Vertex> reArrangePointsByLayersTier(const QVector<Layer>& layers);
    void updateStackIndexRangeInfo(GLint &count, bool increaseOrDecrease);
    GLint m_sliceHead = 0;
    GLint m_slicePointsCount = 0;

private:
    STLModelAttributesCalculator m_model_attr_calculator;
    std::shared_ptr<ISTLModelMeshesConvertor> m_sp_model_vertices_convertor;

private:
    QMatrix4x4 m_model;
    ViewCamera m_camera;
    QVector3D m_lightPos{1.2f, 1.0f, 2.0f}, m_ambientLight{0.2f, 0.2f, 0.2f}, m_diffLight{0.5f, 0.5f, 0.5f}, m_specLight{1.0f, 1.0f, 1.0f}; // 光源相关反射
    QVector3D m_ambientObj{1.0f, 0.5f, 0.31f}, m_diffObj{1.0f, 0.5f, 0.31f}, m_specObj{0.5f, 0.5f, 0.5f}; float shininess = 64.0f; // 物体相关反射

private:
    QOpenGLVertexArrayObject m_vao, m_axis_vao;
    QOpenGLBuffer m_vbo, m_axis_vbo;
    QOpenGLBuffer m_ebo, m_axis_ebo;
    GLuint m_fbo;
    GLuint m_fboTexture;
    QOpenGLShaderProgram *m_p_program = nullptr;
    QOpenGLShaderProgram *m_p_coord_sys_program = nullptr;

private:
    QVector3D m_centroid;
    QVector3D m_initModelPhase;

private:
    std::shared_ptr<STLReader> m_sp_stl_reader = nullptr;
    QVector<Vertex> m_coordSysPoints;
    QVector<Layer> m_stlModelLayers;


private:
    QPoint m_lastMousePos; // 记录上一次鼠标位置
    bool m_isMousePressed = false; // 记录鼠标是否按下
    QVector3D m_rotationAxis = QVector3D(0.0f, 1.0f, 0.0f); // 旋转轴
    float m_rotationAngle = 0.0f; // 旋转角度

private:
    qsizetype m_curShowSlicesIndice = 0;
    qsizetype m_intersected_points_count = 0;
    QVector<qsizetype> m_intersected_points_counts;
    float m_bladeThickness = 0.05f;
};
#endif // STLMODELWIDGET_H
